Podsumowanie

Najczęściej wykorzystywanymi bateriami są baterie litowe. Można dla nich zaobserwować największe średnie napięcie. Często bada się także baterie oparte na magnezie, cynku, wapniu czy sodzie. Baterie oparte na magnezie potrafią osiągnąć znacznie większe wartości zmiany objętności. Model regresji liniowej oparty na średnim napięciu, pojemnościach i one-hot-encodingu głównego jonu średnio radzi sobie w przewidywaniu gęstocíć energii w odniesieniu do masy baterii.

Biblioteki

library(knitr)
library(DT)
library(dplyr)
library(ggplot2)
library(gridExtra)
library(corrplot)
library(caret)
library(tidyr)

Seed

set.seed(2024)

Opis danych

Wczytanie danych

df = read.csv("mp_batteries.csv")
prettyTable(df)

Czyszczenie danych

Average.Voltage, Gravimetric.Energy, Volumetric.Energy przyjmują ujemne wartości z powodu kierunku prądu. Kierunek prądu nie będzie przydatny w tej analizie, więc zastostuję transformację, aby wszystkie wartości były nieujemne.

df <- df %>%
  mutate(
    Average.Voltage = abs(Average.Voltage),
    Gravimetric.Energy = abs(Gravimetric.Energy),
    Volumetric.Energy = abs(Volumetric.Energy)
  )

Podstawowa analiza danych

knitr::kable(summary(df))
Battery.ID Battery.Formula Working.Ion Formula.Charge Formula.Discharge Max.Delta.Volume Average.Voltage Gravimetric.Capacity Volumetric.Capacity Gravimetric.Energy Volumetric.Energy Atomic.Fraction.Charge Atomic.Fraction.Discharge Stability.Charge Stability.Discharge Steps Max.Voltage.Step
Length:4351 Length:4351 Length:4351 Length:4351 Length:4351 Min. : 0.00002 Min. : 0.00306 Min. : 5.176 Min. : 24.08 Min. : 0.205 Min. : 0.936 Min. :0.00000 Min. :0.007407 Min. :0.00000 Min. :0.00000 Min. :1.000 Min. : 0.0000
Class :character Class :character Class :character Class :character Class :character 1st Qu.: 0.01747 1st Qu.: 2.23367 1st Qu.: 88.108 1st Qu.: 311.62 1st Qu.: 215.518 1st Qu.: 834.453 1st Qu.:0.00000 1st Qu.:0.086957 1st Qu.:0.03301 1st Qu.:0.01952 1st Qu.:1.000 1st Qu.: 0.0000
Mode :character Mode :character Mode :character Mode :character Mode :character Median : 0.04203 Median : 3.30211 Median : 130.691 Median : 507.03 Median : 403.139 Median : 1467.835 Median :0.00000 Median :0.142857 Median :0.07319 Median :0.04878 Median :1.000 Median : 0.0000
NA NA NA NA NA Mean : 0.37531 Mean : 3.13564 Mean : 158.291 Mean : 610.62 Mean : 452.161 Mean : 1691.783 Mean :0.03986 Mean :0.159077 Mean :0.14257 Mean :0.12207 Mean :1.167 Mean : 0.1503
NA NA NA NA NA 3rd Qu.: 0.08595 3rd Qu.: 4.02015 3rd Qu.: 187.600 3rd Qu.: 722.75 3rd Qu.: 614.416 3rd Qu.: 2252.257 3rd Qu.:0.04762 3rd Qu.:0.200000 3rd Qu.:0.13160 3rd Qu.:0.09299 3rd Qu.:1.000 3rd Qu.: 0.0000
NA NA NA NA NA Max. :293.19322 Max. :54.56883 Max. :2557.627 Max. :7619.19 Max. :5926.950 Max. :18305.898 Max. :0.90909 Max. :0.993333 Max. :6.48710 Max. :6.27781 Max. :6.000 Max. :26.9607

Zbiór danych zawiera 4351 rekordów, w tym 0 z wartościami pustymi.

Szczegółowa analiza cech

Working Ion

working.ion.count <- df %>%
  count(Working.Ion) %>%
  rename(Count = n)

ggplot(
  working.ion.count,
  aes(
    x = Working.Ion,
    y = Count,
    fill = Working.Ion
  )
) +
  geom_col() +
  labs(
    title = "Ilość unikalnych głównych jonów",
    x = "Główny jon",
    y = "Ilość"
  ) 

Zbiór danych zawiera najwięcej baterii opartych na licie.

Max Delta Volume

Przedział wartości zmiany objętości jest bardzo duży. Wartości poniżej 1 dotyczą 98% zbioru danych. Ale największą wartością jest 293.1932179. Z tego powodu histogram nie za dobrze przedstawi rozkład wartości.

Warto zastanowić się co ma wpływ na bardzo wysokie wartości Max Delta Volume. W dalszej części analizy przyjrzymy się korelacji pomiędzy zmiennymi, aby odpowiedzieć sobie na to pytanie. W tej sekcji sprawdzimy jedynie statystyki Max Delta Volume dla poszczególnych głównych jonów.

df %>%
  group_by(Working.Ion) %>%
  summarise(
    Min.Max.Delta.Volume = min(Max.Delta.Volume),
    Max.Max.Delta.Volume = max(Max.Delta.Volume),
    Mean.Max.Delta.Volume = mean(Max.Delta.Volume),
    SD.Max.Delta.Volume = sd(Max.Delta.Volume),
    Count = n()
  ) %>%
  prettyTable

Magnes zdecydowanie wyróżnia się na tle innych jonów.

Average.Voltage

df %>%
  group_by(Working.Ion) %>%
  summarise(
    Min.Average.Voltage = min(Average.Voltage),
    Max.Average.Voltage = max(Average.Voltage),
    Mean.Average.Voltage = mean(Average.Voltage),
    SD.Average.Voltage = sd(Average.Voltage),
    Count = n()
  ) %>%
  prettyTable

Tym razem największe średnie napięcie można zaobserwować dla baterii litowych.

Capacity

# Histogram dla Gravimetric.Capacity
hist_gravimetric <- ggplot(df, aes(x = Gravimetric.Capacity)) +
  geom_histogram(bins=30) +
  labs(title = "Histogram Gravimetric.Capacity", x = "Geometric Capacity", y = "Częstotliwość")

# Histogram dla Volumetric.Capacity
hist_volumetric <- ggplot(df, aes(x = Volumetric.Capacity)) +
  geom_histogram(bins=30) +
  labs(title = "Histogram Volumetric.Capacity", x = "Volumetric Capacity", y = "Częstotliwość")

grid.arrange(hist_gravimetric, hist_volumetric, ncol=2)

Energy

# Histogram dla Gravimetric.Energy
hist_gravimetric <- ggplot(df, aes(x = Gravimetric.Energy)) +
  geom_histogram(bins=30) +
  labs(title = "Histogram Gravimetric.Energy", x = "Geometric Energy", y = "Częstotliwość")

# Histogram dla Volumetric.Energy
hist_volumetric <- ggplot(df, aes(x = Volumetric.Energy)) +
  geom_histogram(bins=30) +
  labs(title = "Histogram Volumetric.Energy", x = "Volumetric Energy", y = "Częstotliwość")

grid.arrange(hist_gravimetric, hist_volumetric, ncol=2)

Stability

ggplot(df) +
  geom_histogram(aes(x = Stability.Charge), 
                 fill = "yellow", color = "black", alpha = 0.5, 
                 bins=30) +
  geom_histogram(aes(x = Stability.Discharge), 
                 fill = "red", color = "black", alpha = 0.5, 
                 bins = 30) +
  labs(title = "Histogramy Stability.Charge i Stability.Discharge", 
       x = "Wartości", y = "Częstotliwość")

Korelacje między cechami

selected_df <- df %>%
  select(
    Max.Delta.Volume,
    Average.Voltage,
    Gravimetric.Capacity,
    Volumetric.Capacity,
    Gravimetric.Energy,
    Volumetric.Energy,
    Stability.Charge,
    Stability.Discharge,
    Max.Voltage.Step
  )
cor_matrix <- cor(selected_df)
cor_matrix[lower.tri(cor_matrix, diag = TRUE)] <- NA
corrplot(cor_matrix, method = "circle", type = "upper", 
         tl.cex = 0.8, number.cex = 0.7, diag = FALSE, 
         tl.col = "black",
         addCoef.col = "black",
         col=colorRampPalette(c("cornflowerblue", "white", "indianred1"))(200))

Można zaobserwować wysoką korelację pomiędzy Gravimetric.Energy i Volumetric.Energy. Jak również Gravimetric.Capacity i Volumetric.Capacity. A także Stability.Charge i Stability.Discharge. Co ciekawe można także zaobserwować całkiem wysoką korelację pomiędzy Average.Voltage i Gravimetric.Energy.

Predykcja Gravimetric.Energy

Przygotowanie danych

data = df %>%
  select(
    Working.Ion,
    Average.Voltage, 
    Gravimetric.Capacity,
    Volumetric.Capacity,
    Gravimetric.Energy
  ) %>%
  mutate(Working.Ion = as.factor(Working.Ion)) %>%
  mutate(value = 1)  %>% # one-hot-encoding
  spread(Working.Ion, value,  fill = 0 ) 

Podział danych

trainIndex <- createDataPartition(data$Gravimetric.Energy, p = 0.8, list = FALSE)
trainData <- data[trainIndex, ]
testData <- data[-trainIndex, ]

Standaryzacja

preProcessParams <- preProcess(trainData[, c("Average.Voltage", "Gravimetric.Capacity", 
                                             "Volumetric.Capacity")], 
                               method = "range")

trainDataScaled <- predict(preProcessParams, trainData)
testDataScaled <- predict(preProcessParams, testData)

Trening

model <- lm(Gravimetric.Energy ~ ., data = trainDataScaled)

Ewaluacja

predictions <- predict(model, newdata = testDataScaled)
R2 <- cor(predictions, testDataScaled$Gravimetric.Energy)^2

Model uzyskał wartość R^2 równą `r R2.

Wizualizacja

ggplot(data.frame(Actual = testData$Gravimetric.Energy, Predicted = predictions), aes(x = Actual, y = Predicted)) +
  geom_point() +
  geom_abline(slope = 1, intercept = 0, color = "red") +
  labs(title = "Rzeczywiste vs przewidywane wartości",
       x = "Rzeczywiste wartości",
       y = "Przewidywane wartości")